#include "ShortcutTable.h"
#include <algorithm>
#include <iterator>

ShortcutTable::ShortcutTable()
{
}

ShortcutTable::~ShortcutTable()
{
}

// Must check if statement number already exist.
BOOLEAN ShortcutTable::InsertAssign(const INTEGER statement_number)
{
	if (statement_number >= 1 &&
		this->GetStatementType(statement_number) == _NULL)
	{
		assign_store.insert(statement_number);
		statement_store.insert(std::pair<INTEGER, NODETYPE>(statement_number, ASSIGN));
		return true;
	}
	return false;
}

BOOLEAN ShortcutTable::InsertCall(const INTEGER statement_number)
{
	if (statement_number >= 1 &&
		this->GetStatementType(statement_number) == _NULL)
	{
		call_store.insert(statement_number);
		statement_store.insert(std::pair<INTEGER, NODETYPE>(statement_number, CALL));
		return true;
	}
	return false;
}

BOOLEAN ShortcutTable::InsertIf(const INTEGER statement_number)
{
	if (statement_number >= 1 &&
		this->GetStatementType(statement_number) == _NULL)
	{
		if_store.insert(statement_number);
		statement_store.insert(std::pair<INTEGER, NODETYPE>(statement_number, IF));
		return true;
	}
	return false;
}

BOOLEAN ShortcutTable::InsertWhile(const INTEGER statement_number)
{
	if (statement_number >= 1 &&
		this->GetStatementType(statement_number) == _NULL)
	{
		while_store.insert(statement_number);
		statement_store.insert(std::pair<INTEGER, NODETYPE>(statement_number, WHILE));
		return true;
	}
	return false;
}

BOOLEAN ShortcutTable::InsertConstant(const INTEGER constant_value)
{
	auto it = const_store.find(constant_value);
	if (it == const_store.end())
	{
		const_store.insert(constant_value);
		return true;
	}

	return false;
}
	
INTEGER_ARRAY ShortcutTable::GetAllStatement()
{
	INTEGER_ARRAY statements;

	// statements' = assign_store U while_store
	set_union(assign_store.begin(), assign_store.end(), while_store.begin(), while_store.end(), inserter(statements, statements.begin()));

	// statements' = statements U if_store
	set_union(statements.begin(), statements.end(), if_store.begin(), if_store.end(), inserter(statements, statements.begin()));

	// statements' = statements U call_store
	set_union(statements.begin(), statements.end(), call_store.begin(), call_store.end(), inserter(statements, statements.begin()));

	return statements;
}
	
INTEGER_ARRAY ShortcutTable::GetAllProgramLine()
{
	return this->GetAllStatement();
}

// Variables: Use VarTable's GetAllVarNames()
// Procedures: Use ProcTable's GetAllProcNames()
INTEGER_ARRAY ShortcutTable::GetAllAssign()
{
	return assign_store;
}

INTEGER_ARRAY ShortcutTable::GetAllCall()
{
	return call_store;
}

INTEGER_ARRAY ShortcutTable::GetAllIf()
{
	return if_store;
}

INTEGER_ARRAY ShortcutTable::GetAllWhile()
{
	return while_store;
}

INTEGER_ARRAY ShortcutTable::GetAllConstant()
{
	return const_store;
}

NODETYPE ShortcutTable::GetStatementType(const INTEGER statement_number)
{
	if (statement_number >= 1)
	{
		auto it = statement_store.find(statement_number);
		if (it != statement_store.end())
		{
			return it->second;
		}
	}
	
	return _NULL;
}

INTEGER ShortcutTable::GetIfCount()
{
	return if_store.size();
}

INTEGER ShortcutTable::GetCallCount()
{
	return call_store.size();
}

INTEGER ShortcutTable::GetWhileCount()
{
	return while_store.size();
}

INTEGER ShortcutTable::GetAssignCount()
{
	return assign_store.size();
}

INTEGER ShortcutTable::GetConstantCount()
{
	return const_store.size();
}

INTEGER ShortcutTable::GetProgramLineCount()
{
	return GetStatementCount();
}

INTEGER ShortcutTable::GetStatementCount()
{
	return assign_store.size() + while_store.size() + call_store.size() + if_store.size();
}